﻿using LiteDB;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
using TYBase;

namespace TYLitedbBase {
    public delegate void DelegateOnError(string error, Exception ex);

    public class LiteDB_BaseHelper<T> where T : Entity_LiteDB_Base {
        private readonly string tag = typeof(T).Name;

        private void InvokeError(string error, Exception ex) {
            onError?.BeginInvoke($"db:{tag}-path:{FilePath},error:获取数据失败", ex, null, null);
        }

        public event DelegateOnError onError;

        public string FilePath { private set; get; }

        /// <summary>
        /// 传文件名称或者绝对路径
        /// </summary>
        /// <param name="_filePath"></param>
        /// <param name="isFileName"></param>
        public LiteDB_BaseHelper(object _filePath, bool isFileName = true) {
            string filePath = "";
            if (isFileName) {
                filePath = LiteDBHelper.GetFileFullPath(_filePath);
            }
            else {
                filePath = $"{_filePath}";
            }
            lock (LiteComm.lockObj) {
                FileInfo fileInfo = new FileInfo(filePath);
                FilePath = $"{fileInfo.FullName}";
                if (!LiteComm.dicObj.ContainsKey(FilePath)) {
                    var obj = new object();
                    LiteComm.dicObj.Add(FilePath, obj);
                    Log.I($"litedb _start  file:{filePath} add Key");
                }
                else {
                    // obj = LiteComm.dicObj[m_filePath];
                    Log.I($"litedb _start  file:{filePath} get Key");
                }
            }
        }

        public void EnsureIndex<K>(Expression<Func<T, K>> keySelector) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        rtdatas.EnsureIndex(keySelector);
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"EnsureIndex 失败", ex);
            }
        }

        public bool Update(T ret) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        rtdatas.Update(ret);
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"UpdateById 失败", ex);

                return false;
            }
        }

        public int Update(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        return rtdatas.UpdateMany(extend, predicate);
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"UpdateMany 失败", ex);

                return -1;
            }
        }

        public bool GetList(out List<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data = rtdatas.Query().ToList();
                    }
                }
                return true;
            }
            catch (Exception ex) {
                InvokeError($"get 失败", ex);
                data = null;
                return false;
            }
        }

        public K Max<K>(Expression<Func<T, K>> keySelector) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        return rtdatas.Max(keySelector);
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"get 失败", ex);
                return default(K);
            }
        }

        public bool Get(out T data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data = rtdatas.Query().FirstOrDefault();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"get 失败", ex);
                data = null;
                return false;
            }
        }
        //
        public bool GetList<K>(Expression<Func<T, K>> keySelector, out List<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data = rtdatas.Query().OrderBy(keySelector).ToList();
                    }
                }
                return data != null;
            }
            catch (Exception ex) {
                InvokeError($"get 失败", ex);
                data = null;
                return false;
            }
        }


        //Expression<Func<T, K>> keySelector

        public int Count() {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        return rtdatas.Count();
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"get Count", ex);
                return -1;
            }
        }

        public int Count(Expression<Func<T, bool>> predicate) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        return rtdatas.Count(predicate);
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"get Count", ex);
                return -1;
            }
        }

        public bool Insert(IEnumerable<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        rtdatas.Insert(data);
                    }
                }
                return true;
            }
            catch (Exception ex) {
                InvokeError($"insert 失败", ex);
                return false;
            }
        }

        public bool Insert(T data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data.Id = 0;
                        rtdatas.Insert(data);
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"insert 失败", ex);
                return false;
            }
        }

        public bool Exist(Expression<Func<T, bool>> predicate) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        return rtdatas.Exists(predicate);
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Exist Expression:{predicate}", ex);
                return false;
            }
        }
        public bool Delete(Expression<Func<T, bool>> predicate) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        rtdatas.DeleteMany(predicate);
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Delete Expression:{predicate}", ex);
                return false;
            }
        }

        public bool Delete(int id) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取 if (rtdatas == null) return false;
                        rtdatas.Delete(id);
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Delete id:{id}失败", ex);
                return false;
            }
        }

        public bool DeleteAll() {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取  if (rtdatas == null) return false;
                        rtdatas.DeleteAll();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"DeleteAll 失败", ex);
                return false;
            }
        }

        public bool Get(Expression<Func<T, bool>> predicate, out T data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取 if (rtdatas == null)
                        data = rtdatas.Query().Where(predicate).FirstOrDefault();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Get {predicate}失败", ex);
                data = null;
                return false;
            }
        }



        public bool GetList(Expression<Func<T, bool>> predicate, out List<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取

                        data = rtdatas.Query().Where(predicate).OrderBy(x => x.Id).ToList();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Get {predicate}失败", ex);
                data = null;
                return false;
            }
        }
        //public bool Get<K>(Expression<Func<T, K>> keySelector, Expression<Func<T, K>> orderBy, out List<T> data)
        //{
        //    try
        //    {
        //        lock (LiteComm.dicObj[FilePath])
        //        {
        //            using (LiteDatabase db = new LiteDatabase(FilePath))
        //            {
        //                ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
        //                data = rtdatas.Query().OrderBy(orderBy).ToList();
        //            }
        //        }
        //        return data != null;
        //    }
        //    catch (Exception ex)
        //    {
        //        InvokeError($"get 失败", ex);
        //        data = null;
        //        return false;
        //    }
        //}

        public bool GetListByPage(Expression<Func<T, bool>> predicate, int pageIndex, int pageSize, out List<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data = rtdatas.Query().Where(predicate).Offset(pageIndex * pageSize).Limit(pageSize).ToList();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Get {predicate}失败", ex);
                data = null;
                return false;
            }
        }

        public bool GetListByPageOrder<K>(Expression<Func<T, bool>> predicate, Expression<Func<T, K>> keySelector, int pageIndex, int pageSize, out List<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data = rtdatas.Query().Where(predicate).OrderBy(x => x.Id).Offset(pageIndex * pageSize).Limit(pageSize).ToList();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Get {predicate}失败", ex);
                data = null;
                return false;
            }
        }

        public bool GetListByPageDesc<K>(Expression<Func<T, bool>> predicate, Expression<Func<T, K>> keySelector, int pageIndex, int pageSize, out List<T> data) {
            try {
                lock (LiteComm.dicObj[FilePath]) {
                    using (LiteDatabase db = new LiteDatabase(FilePath)) {
                        ILiteCollection<T> rtdatas = db.GetCollection<T>();//获取
                        data = rtdatas.Query().Where(predicate).OrderByDescending(keySelector).Offset(pageIndex * pageSize).Limit(pageSize).ToList();
                        return true;
                    }
                }
            }
            catch (Exception ex) {
                InvokeError($"Get {predicate}失败", ex);
                data = null;
                return false;
            }
        }

    }
}